home *** CD-ROM | disk | FTP | other *** search
/ PC-Blue - MS DOS Public Domain Library / PC-Blue MS-DOS Public Domain Library - NYACC.iso / vol246 / msbmkb.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-12-01  |  10.3 KB  |  339 lines

  1. /* MSBMKB.C
  2.  *
  3.  * Update history:
  4.  *
  5.  * Modified 3/11/86 Howie Kaye -- Columbia University
  6.  * added UNIX and Microsoft C compatibility
  7.  * changed I/O to be buffered
  8.  * note: there is a bug built into the EOF handling which causes the 
  9.  * output file to grow everytime a file is packed/unpacked.  This is 
  10.  * because 2 nulls and a space are added at the end of each run.  As 
  11.  * the data is past the end of the file, it does not affect the program
  12.  * produced.
  13.  *
  14.  * [1]     Version adapted from the DEC-20 code to run on Lattice-C (v 2.14)
  15.  * on an IBM PC/AT under DOS 3.0.      Alan Phillips, Lancaster University UK
  16.  *
  17.  * Original by Bill Catchings, Columbia University, July 1984
  18.  */
  19.  
  20. /*
  21.  * This program takes a file and encodes it into printable characters.
  22.  * These printable files can then be decoded by the programs MSPCBOOT.BAS
  23.  * or MSPCTRAN.BAS as the need may be.    The file is encoded by taking
  24.  * three consecutive eight bit bytes and dividing them into four six bit
  25.  * bytes.  An ASCII zero was then added to the resulting four characters.
  26.  * to make them all printable ASCII characters in the range of the
  27.  * character zero to the character underscore.    In order to reduce the
  28.  * size of the file null repeat count was used.  The null repeat count
  29.  * compresses up to 78 consecutive nulls into only two characters.  This
  30.  * is done by using the character tilde (~) as an indication that a group
  31.  * of repetitive nulls has occured.  The character following the tilde is
  32.  * number of nulls in the group.  The number is also converted in to a
  33.  * printable character by adding an ASCII zero.  The highest number of
  34.  * nulls is therefore the highest printable character tilde.  This is
  35.  * equal to tilde minus zero nulls or 78 nulls.  Because of the three
  36.  * byte to four byte encoding the repeat counting can only start with
  37.  * the first character of a three byte triplet.
  38.  *
  39.  * This C program was written specifically for the DEC-20 and as such
  40.  * will not easily be transported to another system.  The main problem
  41.  * lies in the file I/O routines.  It is necessary to make sure that
  42.  * untranslated eight bit bytes are input from the input file.    The
  43.  * main change would be to make the OPEN statement reflect this for
  44.  * your particular system and brand of UNIX and C.  The rest of the
  45.  * program should be transportable with little or no problems.
  46.  */
  47.  
  48. /*
  49.  * set msdos if to be compiled on an msdos machine 
  50.  */     
  51.  
  52. #define MSDOS     -1
  53. #define UNIX    0
  54. #define TOPS20  0
  55.  
  56. #include <stdio.h>        /* Standard UNIX i/o definitions */
  57.  
  58. #if    MSDOS         /* [1] */
  59. #include <fcntl.h>
  60. #endif
  61. #if UNIX
  62. #include <sys/file.h>
  63. #endif                /* [1] */
  64. #if TOPS20
  65. #include <file.h>
  66. #endif
  67.  
  68. /* Symbol Definitions */
  69.  
  70. #define MAXPACK     80    /* Maximum packet size */
  71.  
  72. #define MYRPTQ        '~'     /* Repeat count prefix I will use */
  73. #define DATALEN     78    /* Length of data buffer */
  74.  
  75. #define TRUE        -1    /* Boolean constants */
  76. #define FALSE        0
  77.  
  78. /* Macros */
  79.  
  80. #define tochar(ch)  ((ch) + '0')
  81.  
  82. /* Global Variables */
  83.  
  84. int    maxsize,        /* Max size for data field */
  85.     fd,            /* File pointer of file to read/write */
  86.     ofd,
  87. #if    !(MSDOS | UNIX)        /* [1] */
  88.     nc,            /* Count of input characters */
  89.     oc,            /* Count of output characters */
  90.     otot,            /* What char number we are processing */
  91. #endif
  92.     rpt,            /* repeat count */
  93.     rptq,            /* repeat quote */
  94.     rptflg,         /* repeat processing flag */
  95.     size,            /* size of present data */
  96. #if    (MSDOS|UNIX)         /* [1] */
  97.     t,            /* Current character value as 16 bit */
  98. #endif                /* [1] */
  99.     eoflag;         /* Set when file is empty. */
  100.  
  101. #if    (MSDOS|UNIX)         /* [1] */
  102. long    nc,            /* Count of input characters */
  103.     oc,            /* Number of output chars */
  104.     otot;            /* What char number we are processing */
  105. #endif                /* [1] */
  106.  
  107. char    one,
  108.     two,
  109.     three,
  110. #if    !(MSDOS|UNIX)        /* [1] */
  111.     t,            /* Current character */
  112. #endif                /* [1] */
  113.     *filnam,        /* Current file name */
  114.     *ofile,
  115.     packet[MAXPACK];    /* Packet buffer */
  116.  
  117. main(argc,argv)             /* Main program */
  118. int argc;                /* Command line argument count */
  119. char **argv;                /* Pointers to args */
  120. {
  121.     char sfile();            /* Send file routine & ret code */
  122.     if (--argc != 2) usage();        /* Make sure there's a command line. */
  123.     rptq = MYRPTQ;            /* Repeat Quote */
  124.     rptflg = TRUE;            /* Repeat Count Processing Flag */
  125.  
  126.     filnam = *++argv;            /* Get file to send */
  127.     ofile = *++argv;            /* Output file to create */
  128.     sfile();
  129. #if    (MSDOS|UNIX)             /* [1] */
  130.     printf("Done, in: %ld, out: %ld, efficiency: %.2f%%\n",nc,oc,(100.0*nc)/oc);
  131. #else
  132.     printf("Done, in: %d, out: %d, efficiency: %.2f%%\n",nc,oc,(100.0*nc)/oc);
  133. #endif                    /* [1] */
  134. }
  135.  
  136. /*
  137.    S F I L E - Send a whole file
  138. */
  139.  
  140. char sfile()                /* Send a file */
  141. {
  142.     char *i;
  143.  
  144. #if    MSDOS             /* [1] */
  145. #ifndef O_RAW
  146. #define O_RAW O_BINARY
  147. #endif O_RAW
  148. #endif MSDOS
  149. #if UNIX
  150. #define O_RAW 0
  151. #endif UNIX
  152. #if (MSDOS | UNIX)
  153.     fd = open(filnam,O_RDONLY | O_RAW,0x1ff);
  154. #else
  155.     fd = open(filnam,FATT_RDONLY | FATT_BINARY | FATT_DEFSIZE,0x1ff);
  156. #endif                    /* [1] */
  157.     if (fd < 0)             /* Report any errors */
  158.     {
  159.     printf("\n?Error opening file \"%s\"\n",filnam);
  160.     exit(1);
  161.     }
  162.  
  163. #if (MSDOS | UNIX)
  164.     ofd = open(ofile,O_CREAT|O_WRONLY|O_TRUNC|O_RAW,0x1ff);
  165. #else
  166.     ofd = open(ofile,FATT_WRONLY | FATT_CREATE | FATT_BINARY,0x1ff);
  167. #endif                    /* [1] */
  168.  
  169.     if (ofd < 0)
  170.     {
  171.     printf("\n?error opening file \"%s\"\n",ofile);
  172.     exit(1);
  173.     }
  174.  
  175.     oc = strlen(filnam);        /* Get the string length. */
  176.     for (i=filnam; *i != '\0'; i++)     /* Uppercase the file name. */
  177.     if (*i >= 'a' && *i <= 'z') *i ^= 040;
  178.     write(ofd,filnam,oc);        /* Write the file name in the file. */
  179. #if (!UNIX)
  180.     write(ofd,"\r\n",2);
  181. #else
  182.     write(ofd,"\n",1);
  183. #endif
  184.     maxsize = DATALEN - 5;
  185.     rpt = 0;                /* Zero the repeat count. */
  186.     oc = nc = 0;            /* Output & input character counts. */
  187.     otot = 1;                /* Start with first char of triplet. */
  188.     while (getbuf() > 0)        /* While not EOF, get a packet. */
  189.     {
  190. #if !(UNIX)
  191.     packet[size++] = '\r';          /* Explicit CRLF. */
  192. #endif
  193.     packet[size++] = '\n';
  194.     packet[size] = '\0';
  195.     oc += size;            /* Count output size. */
  196.     write(ofd,packet,size);     /* Write the packet to the file. */
  197.      /* printf("%d: %s",size,packet);*/ /* Print on the screen for testing. */
  198.     }
  199. #if    MSDOS             /* [1] */
  200.     close(fd);                /* close the files neatly */
  201.     close(ofd);
  202. #endif                    /* [1] */
  203. }
  204. /*
  205.    G E T B U F -- Do one packet.
  206. */
  207.  
  208. getbuf()               /* Fill one packet buffer. */
  209. {
  210.     if (eoflag != 0) return(-1);    /* If at the end of file, stop. */
  211.     size = 0;
  212.     while((t = getch()) >= 0)        /* t == -1 means EOF. */
  213.     {
  214.     nc++;                /* Count the character. */
  215.     process(t);            /* Process the character. */
  216.     if (size >= maxsize)        /* If the packet is full, */
  217.     {
  218.         packet[size] = '\0';        /*  terminate the string. */
  219.         return(size);
  220.     }
  221.     }
  222.     eoflag = -1;            /* Say we hit the end of the file. */
  223.     process(0);             /* Clean out any remaining chars. */
  224.     process(0);
  225.     process(' ');
  226.     packet[size] = '\0';                /* Return any partial final buffer. */
  227.     return(size);
  228. }
  229.  
  230. /* P R O C E S S -- Do one character. */
  231.  
  232. process(a)
  233. char a;
  234. {
  235.     if (otot == 1)            /* Is this the first of three chars? */
  236.     {
  237.     if (a == 0)            /* Is it a null? */
  238.     {
  239.         if (++rpt < 78)        /* Below max nulls, just count. */
  240.         return;
  241.         else if (rpt == 78)     /* Reached max number, must output. */
  242.         {
  243.         packet[size++] = rptq;    /* Put in null repeat char and */
  244.         packet[size++] = tochar(rpt); /* number of nulls. */
  245.         packet[size] = '\0';
  246.         rpt = 0;
  247.         return;
  248.         }
  249.     }
  250.     else
  251.     {
  252.         if (rpt == 1)        /* Just one null? */
  253.         {
  254.         one = 0;        /* Say the first char was a null. */
  255.         two = a;        /* This char is the second one. */
  256.         otot = 3;        /* Look for the third char. */
  257.         rpt = 0;        /* Restart null count. */
  258.         return;
  259.         }
  260.         if (rpt > 1)        /* Some number of nulls? */
  261.         {
  262.         packet[size++] = rptq;    /* Insert the repeat prefix */
  263.         packet[size++] = tochar(rpt); /* and count. */
  264.         packet[size] = '\0';
  265.         rpt = 0;        /* Reset repeat counter. */
  266.         }
  267.         one = a;            /* Set first character. */
  268.         otot = 2;            /* Say we are at the second char. */
  269.     }
  270.     }
  271.     else if (otot == 2)
  272.     {
  273.     two = a;            /* Set second character. */
  274.     otot = 3;            /* Say we are at the third char. */
  275.     }
  276.     else
  277.     {
  278.     three = a;
  279.     otot = 1;            /* Start over at one. */
  280.     pack(one,two,three);        /* Pack in the three characters. */
  281.     }
  282. }
  283.  
  284. /* This routine does the actual three character to four character encoding.
  285.  * The concept is relatively straight forward.    The first output character
  286.  * consists of the first (high order or most significant) six bits of the
  287.  * first input character.  The second output character is made from the
  288.  * remaining two low order bits of the first input character and the first
  289.  * four high order bits of the second input character.    The third output
  290.  * character is built from the last four low order bits of the second input
  291.  * character and the two high order bits of the third input character.    The
  292.  * fourth and last output character consists of the six low order bit of
  293.  * the third input character.  In this way the three eight bit input char-
  294.  * acters (for a total of 24 bits) are divided into four six bit output
  295.  * characters (also for a total of 24 bits).  In order to make the four
  296.  * output characters printable an ASCII zero is then added to each of them.
  297.  *
  298.  */
  299.  
  300. pack(x,y,z)
  301. char x,y,z;
  302. {
  303.     packet[size++] = tochar((x >> 2) & 077);
  304.     packet[size++] = tochar(((x & 003) << 4) | ((y >> 4) & 017));
  305.     packet[size++] = tochar(((y & 017) << 2) | ((z >> 6) & 003));
  306.     packet[size++] = tochar(z & 077);
  307.     packet[size] = '\0';
  308. }
  309.  
  310. int
  311. getch()                 /* Get next (or pushed) char. */
  312. {
  313. #if TOPS20
  314.                     /* really really inefficient. */
  315.    return((read(fd,&a,1) > 0) ? (int) (a&0xff) : -1); /* (or -1 if EOF) */
  316. #else
  317. #ifndef BSIZE
  318. #define BSIZE 500
  319. #endif
  320.    static int index = 0, count = 0;
  321.    static char buf[BSIZE];
  322.  
  323.    if (count == 0) {
  324.      count = read(fd,buf,BSIZE);
  325.      if (count <= 0) return(-1);
  326.      index = 0;
  327.    }
  328.    count--;
  329.    return(buf[index++]&0xff);
  330.  
  331. #endif
  332. }
  333.  
  334. usage()                 /* Give message if user makes */
  335. {                    /* a mistake in the command. */
  336.     fprintf(stderr,"usage: msmkboo inputfile outputfile\n");
  337.     exit(1);
  338. }
  339.